﻿using AutoMapper;
using Benefactor.Models.DbModels;
using Benefactor.Models.DtoModels;
using Benefactor.Services.Repositories;
using Bigway.Common.Models.DtoModels;
using Bigway.Common.Services.Repositories;
using Microsoft.AspNetCore.Mvc;
using IAppConfig = Benefactor.Services.IAppConfig;

namespace Benefactor.Controllers;
using static Errors;

[ApiController]
[Route("api/product")]
public class ProductController(
    IProductTypeRepository productTypeRepository,
    IProductRepository productRepository,
    ISoftwareSystemRepository softwareSystemRepository,
    IMapper mapper,
    IAppConfig appConfig,
    ILogger<ProductController> logger) : ControllerBase
{
    [HttpPost]
    public async Task<AddProductResponseDto> AddProductAsync(
        [FromQuery(Name = "api_key")] string apiKey,
        [FromBody] AddProductRequestDto request,
        CancellationToken token = default
    )
    {
        var systemId = request.SystemId;
        logger.LogInformation("Adding product for system {SystemId}", systemId);
        if (apiKey != appConfig.ApiKey)
            return Unauthorized<AddProductResponseDto>();

        var system = await softwareSystemRepository.GetAsync(systemId, token);
        if (system is null)
            return SystemNotFound<AddProductResponseDto>(systemId);

        var productTypes = await productTypeRepository.GetAllAsync(request.SystemId,
            request.ProductTypeCode, token);
        if (productTypes.Count == 0)
            return ProductTypeCodeNotFound<AddProductResponseDto>(request.ProductTypeCode);

        var product = await productRepository.AddAsync(
            mapper.Map<Product>(request), token);

        return new AddProductResponseDto
        {
            Data = mapper.Map<ProductInfo>(product)
        };
    }

    [HttpPut]
    public async Task<NoDataResponseDto> UpdateProductAsync(
        [FromQuery(Name = "api_key")] string apiKey,
        [FromBody] UpdateProductRequestDto request,
        CancellationToken token = default
    )
    {
        var productId = request.Id;
        logger.LogInformation("Updating product of id {ProductId}", productId);
        if (apiKey != appConfig.ApiKey)
            return Unauthorized<NoDataResponseDto>();

        var product = await productRepository.GetByIdAsync(productId, token);
        if (product is null)
            return ProductNotFound<NoDataResponseDto>(productId);
        else if (product.IsDeleted)
            return ProductDeleted<NoDataResponseDto>(productId);

        var productTypes = await productTypeRepository.GetAllAsync(request.SystemId,
            request.ProductTypeCode, token);
        if (productTypes.Count == 0)
            return ProductTypeCodeNotFound<NoDataResponseDto>(request.ProductTypeCode);

        product = mapper.Map(request, product);
        
        await productRepository.UpdateAsync(product, token);
        return new NoDataResponseDto();
    }

    [HttpDelete]
    public async Task<NoDataResponseDto> DeleteProductAsync(
        [FromQuery(Name = "api_key")] string apiKey,
        [FromBody] DeleteEntityRequestDto request,
        CancellationToken token = default
    )
    {
        var productId = request.Id;
        logger.LogInformation("Deleting product of id {ProductId}",
            productId);
        if (apiKey != appConfig.ApiKey)
            return Unauthorized<NoDataResponseDto>();

        var product = await productRepository.GetByIdAsync(productId, token);
        if (product is null)
            return ProductNotFound<NoDataResponseDto>(productId);
        else if (product.IsDeleted)
            return ProductDeleted<NoDataResponseDto>(productId);

        product.IsDeleted = true;

        await productRepository.UpdateAsync(product, token);

        return new NoDataResponseDto();
    }

    [HttpGet]
    public async Task<GetProductsResponseDto> GetProductsAsync(
        [FromQuery(Name = "api_key")] string apiKey,
        [FromQuery] GetProductsRequestDto request,
        CancellationToken token = default
    )
    {
        var systemId = request.system_id;
        var merchantIds = request.merchant_ids;
        var productId = request.product_id;
        logger.LogInformation("Getting products for system {SystemId}", systemId);
        if (apiKey != appConfig.ApiKey)
            return Unauthorized<GetProductsResponseDto>();

        var system = await softwareSystemRepository.GetAsync(systemId, token);
        if (system is null)
            return SystemNotFound<GetProductsResponseDto>(systemId);

        var products = await productRepository.GetAllAsync(
            query =>
            {
                query = query.Where(x => x.SystemId == systemId && !x.IsDeleted);

                if (merchantIds is {Length: > 0})
                    query = query.Where(x => merchantIds.Contains(x.MerchantId));
                if (!string.IsNullOrEmpty(productId))
                    query = query.Where(x => x.Id == productId);

                query = query.OrderByDescending(x => x.CreateTime);
                return query;
            }, token);

        var productInfos = products.Select(mapper.Map<ProductInfo>);
        return new GetProductsResponseDto
        {
            Data = productInfos
        };
    }
}